﻿// Original author contact info: Owen Emlen (owene_1998@yahoo.com)
// Note: other individuals may also have contributed to this code
// Project hosted on CodePlex.com as of 1/10/2009 at http://www.codeplex.com/EmlenMud
using System.Runtime.Serialization;
using System.Collections;
using System.Xml.Serialization;
using System.ComponentModel;
using System.Collections.Specialized;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading;
using BrainTechLLC.ThreadSafeObjects;

namespace BrainTechLLC
{
    [DataContract]
    [Serializable]
#if NO_SILVERLIGHT
    [Browsable(true)]
    [TypeConverter(typeof(ExpandableObjectConverter))]
    [EditorBrowsable(EditorBrowsableState.Always)]
#endif
    public class State : GameThingBaseClass, IExecutableWorkItem, IFromTemplate
    {
        [DataMember]
        public string _stateName;

        [DataMember]
#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        public int AutoScheduleMS { get; set; }

        [NonSerialized, XmlIgnore]
        public bool _scheduled;

#if NO_SILVERLIGHT
        [OnDeserialized]
        public void PostDeserialization(StreamingContext context)
        {
            PerformPostRestoreSetup();
        }
#endif

        public override void PerformPostRestoreSetup()
        {
            Register();
        }

        [DataMember]
        public CommandToPerform _baseStateAction;

        [NonSerialized, XmlIgnore]
        //[DataMember]
        public ThreadSafeList<State> _modifications;

        [DataMember]
        public ThreadSafeLookup<string, CommandToPerform> _modifyExecutingState;

        [DataMember]
        public int _baseRescheduleFrequency;

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        [XmlIgnore]
        public int RescheduleFrequency { get; set; }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        public int BaseRescheduleFrequency { get { return _baseRescheduleFrequency; } set { _baseRescheduleFrequency = value; } }

        [NonSerialized, XmlIgnore]
        protected StateCollection _parentStateCollection;

        public override void Register()
        {
            base.Register();
        }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        public long AssociatedWith
        {
            get { return _parentStateCollection == null ? 0 : _parentStateCollection.AssociatedWith; }
        }

        public void ExecuteStateUpdate()
        {
            // Allow relevant modifying states to change state parameters
            bool doNotPerform = false;
            bool doNotReschedule = false;
            RescheduleFrequency = _baseRescheduleFrequency;
            BaseStateAction.ApplyToID = AssociatedWith;
            PropertyData ArgumentsCopy = ThingProperties;

            if (_modifications != null)
            {
                ArgumentsCopy = ThingProperties.MakeCopy();
                for (int n = 0; n < _modifications._list.Count; n++)
                {
                    State state = _modifications._list[n];
                    CommandToPerform modifier = state.ModifyExecutingState[_stateName];
                    modifier.ExecutingState = state;
                    modifier.Arguments = ArgumentsCopy;
                    modifier.ApplyToID = AssociatedWith;
                    modifier.ModifyingArguments = state.ThingProperties;

                    modifier.Perform();

                    modifier.ModifyingArguments = null;
                    modifier.ExecutingState = null;

                    if (modifier.CommandOutput != null &&
                         modifier.CommandOutput.ToString().IndexOf("DoNotPerformStateUpdate") >= 0)
                    {
                        doNotPerform = true;
                    }
                    if (modifier.CommandOutput != null &&
                         modifier.CommandOutput.ToString().IndexOf("DoNotReschedule") >= 0)
                    {
                        doNotReschedule = true;
                    }
                }
            }

            if (!doNotPerform)
            {
                _baseStateAction.Arguments = ArgumentsCopy;
                _baseStateAction.ExecutingState = this;
                _baseStateAction.Perform();
                _baseStateAction.ModifyingArguments = null;
                _baseStateAction.ExecutingState = null;

                if (RescheduleFrequency > 0)
                {
                    // reschedule
                    if (!doNotReschedule)
                    {
                        Globals.SchedulingEngine.ScheduleEventToExecute(this, RescheduleFrequency);
                    }
                }
            }
        }

        [EditorBrowsable(EditorBrowsableState.Advanced)]
        [XmlIgnore]
        [DoNotWriteBack]
        public StateCollection ParentStateCollection
        {
            get
            {
                if (_parentStateCollection == null)
                    Interlocked.CompareExchange<StateCollection>(ref _parentStateCollection, new StateCollection(), null);

                return _parentStateCollection;
            }
            set
            {
                _parentStateCollection = value;
            }
        }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        [XmlIgnore]
        public CommandToPerform BaseStateAction
        {
            get { return _baseStateAction; }
            set { _baseStateAction = value; }
        }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        [XmlIgnore]
        public string StateName
        {
            get { return _stateName; }
            set { _stateName = value; }
        }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        [XmlIgnore]
        [DoNotWriteBack]
        public ThreadSafeList<State> Modifications
        {
            get
            {
                if (_modifications == null)
                    Interlocked.CompareExchange<ThreadSafeList<State>>(ref _modifications, new ThreadSafeList<State>(), null);

                return _modifications;
            }
            set
            {
                _modifications = value;
            }
        }

#if NO_SILVERLIGHT
        [EditorBrowsable(EditorBrowsableState.Always)]
#endif
        [XmlIgnore]
        public ThreadSafeLookup<string, CommandToPerform> ModifyExecutingState
        {
            get
            {
                if (_modifyExecutingState == null)
                    Interlocked.CompareExchange<ThreadSafeLookup<string, CommandToPerform>>(ref _modifyExecutingState, new ThreadSafeLookup<string, CommandToPerform>(), null);

                return _modifyExecutingState;
            }
            set
            {
                _modifyExecutingState = value;
            }
        }

        [XmlIgnore, NonSerialized]
        protected DateTime _executionTime;

        [XmlIgnore, NonSerialized]
        protected bool _cancelled;

        [XmlIgnore]
        [DoNotWriteBack]
        public DateTime ExecutionTime { get { return _executionTime; } set { _executionTime = value; } }

        [XmlIgnore]
        [DoNotWriteBack]
        public bool Cancelled { get { return _cancelled; } set { _cancelled = value; } }

        public void Execute()
        {
            ExecuteStateUpdate();
        }
    }
}
